-module(sctp_pair_server).
-behaviour(gen_server).
-export([start/0,start_link/0,start_link/1,init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
-export([handle/2]).
-include("protocol.hrl").
-define(SERVER,?MODULE).
-define(HEARTBEAT,4).
-define(HEARTBEAT_ACK,5).
-define(SELECT_ACK,3).
-define(DATA,0).
-record(sctp_counter,{
	heartbeat = 0,
	heartbeat_ack = 0,
	data = 0,
	select_ack = 0,
	unknown = 0
	}).
handle(Pid,Request) ->
	gen_server:cast(Pid,Request).

start()  ->
	gen_server:start({local, ?SERVER}, ?MODULE, [], []).

start_link(Sctp_Pair) ->
	gen_server:start_link(?MODULE, [Sctp_Pair], []).

start_link() ->
	start_link(undefined).

init([Sctp_Pair]) ->
%%	error_logger:info_msg("sctp pair server ~w start...~n",[Sctp_Pair]),
	process_flag(trap_exit, true),
	{IP1,Port1,IP2,Port2} = Sctp_Pair,
	{ok,{running,{{},#sctp_counter{}}}}.
handle_call(dump_dict,_,State) ->
	io:format("S1-Session List:~n~p",[get()]),
	{reply,ok,State};

handle_call(_,_,State) ->
	{reply, {error,"no func define sctp server"}, State}.

handle_cast({packet_comming,P_Tuple},State) ->
	<< _Source_Port:16,_Dest_Port:16,_Other:64,Data/binary>> = P_Tuple#packet_tuple.packet,
	IPContext = packet_tool:get_cxt(ip,P_Tuple#packet_tuple.context),
  L1_Cxt = packet_tool:get_cxt(l1,P_Tuple#packet_tuple.context),
	NewState = handle_trunks({L1_Cxt#l1_protocol.index,L1_Cxt#l1_protocol.coming_datetime},Data,{IPContext,State}),
	{noreply,NewState};

handle_cast(Request, State) ->
	error_logger:format("unkown request received~p~n",[Request]),
	{noreply,State}.
handle_info(_, State) ->
	{noreply,State}.
terminate(_, _) ->
	ok.
code_change(_, State, _) ->
	{ok,State}.

handle_trunks({Index,DateTime},Data,{IPContext,State}) when byte_size(Data) > 4 ->
	<<Chunk_Type:8,_Chunk_Flag:8,Length:16/integer,Other/binary>> = Data,
	P_Size = (Length - 4),
	Padding = case Length rem 4 of
			  0 ->
				  0;
			  A ->
				  4 - A
			  end,
	<<Payload1:P_Size/binary,_Padding:Padding/binary,OtherTrunks/binary>> = Other,
    case Index of
    12 ->
      io:format("the first payloadsize:~p DataSize:~p, other:~p",[P_Size,byte_size(Data),OtherTrunks]);
    _ ->
      ok
    end,
	handle_trunks({Index,DateTime},OtherTrunks,{IPContext,handle_trunk({Index,DateTime},{Chunk_Type,Payload1},{IPContext,State})});

handle_trunks({Index,DateTime},Data,{_Sctp_Pair,State}) ->
  case Index of
  undefined ->
     io:format("other trunk eq ~p~n",[Data]);
  _ ->
     ok
  end,
	State.

handle_trunk({Index,DateTime},{?DATA,Trunk},{IPContext,{running,{Sctp_Cxt,Counter}}}) ->
	<<_TSN:32,_Stream_Id:16,_Stream_No:16,Payload_Id:32,Payload/binary>> = Trunk,
	New_Sctp_Cxt = case Payload_Id of
	              18 ->
		              s1ap_ana:do(asn1binary,{IPContext,Sctp_Cxt,Payload},{Index,DateTime});
	              _ ->
		              Sctp_Cxt
	              end,
	{running,{New_Sctp_Cxt,Counter#sctp_counter{data = Counter#sctp_counter.data + 1}}};

handle_trunk({Index,DateTime},{?SELECT_ACK,Trunk},{_Sctp_Pair,{running,{Sctp_Cxt,Counter}}}) ->
	{running,{Sctp_Cxt,Counter#sctp_counter{select_ack = Counter#sctp_counter.select_ack + 1}}};

handle_trunk({Index,DateTime},{?HEARTBEAT,Trunk},{_Sctp_Pair,{running,{Sctp_Cxt,Counter}}}) ->
  {running,{Sctp_Cxt,Counter#sctp_counter{heartbeat = Counter#sctp_counter.heartbeat + 1}}};

handle_trunk({Index,DateTime},{?HEARTBEAT_ACK,Trunk},{_Sctp_Pair,{running,{Sctp_Cxt,Counter}}}) ->
	{running,{Sctp_Cxt,Counter#sctp_counter{heartbeat_ack = Counter#sctp_counter.heartbeat_ack + 1}}};

handle_trunk({Index,DateTime},_,{_Sctp_Pair,{running,{Sctp_Cxt,Counter}}}) ->
  {running,{Sctp_Cxt,Counter#sctp_counter{unknown = Counter#sctp_counter.unknown + 1}}}.

